/**
 * 
 */
package com.alstudio.module.xmpp.protocol.xmpp.util.openstream;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

import android.os.Handler;
import android.text.TextUtils;

import com.alstudio.module.xmpp.protocol.xmpp.ALXmlReader;
import com.alstudio.module.xmpp.protocol.xmpp.ALXmlWriter;
import com.alstudio.module.xmpp.protocol.xmpp.ALXmppEventListener;
import com.alstudio.module.xmpp.protocol.xmpp.ALXmppListener;
import com.alstudio.module.xmpp.protocol.xmpp.ALXmppParseConfigue;
import com.alstudio.module.xmpp.protocol.xmpp.data.ALXmppData;
import com.alstudio.module.xmpp.protocol.xmpp.packact.ALIQ;
import com.alstudio.module.xmpp.protocol.xmpp.packact.ALIQType;
import com.alstudio.module.xmpp.protocol.xmpp.packact.IQNameSpace;
import com.alstudio.module.xmpp.protocol.xmpp.util.xmlcreator.iq.BaseIQTemplate;
import com.alstudio.utils.android.net.AndroidNetUtils;
import com.alstudio.utils.log.ALLog;

/**
 * @author alonso lee
 * 
 */
public class OpenStreamUtil {

	private Socket localSocket;
	private Handler mHandler;
	private InputStream in;
	private OutputStream out;
	private String ip;
	private String port;
	private BaseIQTemplate iq;
	private ALXmlReader reader;
	private ALXmlWriter writer;
	private String domain;

	private static OpenStreamUtil instance;
	private static ALXmppParseConfigue parserConfigue;

	private ALXmppEventListener listener = null;

	public static OpenStreamUtil getDefaultUtil() {
		if (instance == null) {
			instance = new OpenStreamUtil();
			parserConfigue = new ALXmppParseConfigue();
		}
		return instance;
	}

	public void startPostIq(ALXmppData data, BaseIQTemplate iq,
			ALXmppEventListener listener) {
		closeStream();
		closeSocket();
		this.ip = data.getHost();
		this.port = data.getPort();
		this.iq = iq;
		this.domain = data.getDomain();
		this.listener = listener;
		ALLog.d("開始創建新連接");

		new Thread(postIqTask).start();

	}

	private Runnable postIqTask = new Runnable() {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			try {
				localSocket = AndroidNetUtils.buildSocketConnection(ip, port);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			ALLog.d("連接已建立");

			try {
				in = localSocket.getInputStream();
				out = localSocket.getOutputStream();
				writer = new ALXmlWriter(out);
				reader = new ALXmlReader(in);
				// 打開流
				if (openStream()) {
					// 打開流成功
					writer.write(iq.toString());
				} else {
					// 打開流失敗，囘調通知
				}
				// 開始解析
				parse();

			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				closeStream();
				closeSocket();
				ALLog.d("斷開當前連接");
			}
		}
	};

	/**
	 * 开始解析
	 * 
	 * @throws IOException
	 */
	private void parse() throws IOException {

		while (this.reader.next() == ALXmlReader.START_TAG) {
			final String tmp = this.reader.getName();

			if (tmp.equals("iq")) {
				this.parseIq();
			} else {
				this.parseIgnore();
			}
		}

		ALLog.e("leave parse() " + reader.getName());
		this.reader.close();

	}

	/**
	 * This method doesn't parse tags it only let the reader go through unknown
	 * tags.
	 * 
	 * @throws java.io.IOException
	 *             is thrown if {@link ALXmlReader} or {@link ALXmlWriter} throw
	 *             an IOException.
	 */
	private void parseIgnore() throws IOException {
		int x;
		while ((x = this.reader.next()) != ALXmlReader.END_TAG) {
			if (x == ALXmlReader.START_TAG) {
				this.parseIgnore();
			}
		}
	}

	/**
	 * This method parses all info/query stanzas, including authentication
	 * mechanism and roster. It also answers version queries.
	 * 
	 * @throws java.io.IOException
	 *             is thrown if {@link ALXmlReader} or {@link ALXmlWriter} throw
	 *             an IOException.
	 */
	private void parseIq() throws IOException {

		String type = this.reader.getAttribute("type");
		final String id = this.reader.getAttribute("id");
		final String from = this.reader.getAttribute("from");
		String to = this.reader.getAttribute("to");
		String ns = "";
		ALIQ iqPackact = new ALIQ(from, to, id);
		iqPackact.setType(getIQType(type));

		while (true) {
			reader.next();
			String tagname = reader.getName();
			if (tagname != null) {
				if ((reader.getType() == ALXmlReader.START_TAG)
						&& tagname.equals("query")) {
					ns = reader.getAttribute("xmlns");
					iqPackact.setNameSpace(ns);
				} else if ((reader.getType() == ALXmlReader.END_TAG)
						&& tagname.equals("ping")) {
					ns = reader.getAttribute("xmlns");
					iqPackact.setNameSpace(ns);

				} else if ((reader.getType() == ALXmlReader.END_TAG)
						&& tagname.equals("iq")) {
					break;
				}
			}
		}

		parserConfigue.getIQParser(iqPackact, reader.buf.toString(), listener);
		printRecvMsg();
		if (IQNameSpace.NS_REGISTER.equals(ns)
				|| IQNameSpace.NS_THIRD_PART_LOGIN.equals(ns)
				|| IQNameSpace.NS_EMAIL_CHECK.equals(ns)) {
			ALLog.d("断开流" + ns);
			closeSocket();
		}
	}

	/**
	 * 打开流
	 * 
	 * @return true 表示打开流成功
	 * @author Alonso Lee
	 */
	private boolean openStream() {
		String msg = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='"
				+ domain + "' version='1.0'>";
		try {
			out.write(msg.getBytes());
			ALLog.d("SEND: " + msg);
		} catch (IOException e) {
			ALLog.e("Open Stream Error: " + e.toString());
			return false;
		}
		try {
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}

		/* 解析服务器打开流消息 */
		parseOpenStream();

		// 打印接收到的XML信息
		printRecvMsg();
		return true;
	}

	/**
	 * 此方法用于解析服务器返回的打开流。
	 * 
	 * @return
	 * @author alonso lee
	 */
	int t = -1;

	private boolean parseOpenStream() {
		int c = -1;
		while (true) {
			t = c;
			try {
				c = reader.getNextCharacter();
			} catch (IOException e) {
				e.printStackTrace();
				return false;
			}

			if (c != -1) {
				if (c == '>' && t == '\'') {
					ALLog.d("open stream parse completed");
					return true;
				}
			}
		}
	}

	/**
	 * 此方法仅供此类输出接收到得xmpp消息
	 * 
	 * @author alonso lee
	 */
	private void printRecvMsg() {
		ALLog.d("RECV: " + reader.buf.toString());
		reader.buf.setLength(0);
	}

	private void closeSocket() {
		if (localSocket != null) {
			try {
				localSocket.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	private void closeStream() {
		try {
			if (in != null) {
				in.close();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		try {
			if (out != null) {
				out.close();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		if (reader != null) {
			reader.close();
		}
		if (writer != null) {
			writer.close();
		}

		reader = null;
		writer = null;
	}

	/**
	 * 将iq的字符串转为IQType
	 * 
	 * @param type
	 * @return
	 */
	private ALIQType getIQType(String type) {
		ALIQType mType = null;
		if (!TextUtils.isEmpty(type)) {
			if (type.equals("error")) {
				mType = ALIQType.ERROR;
			} else if (type.equals("set")) {
				mType = ALIQType.SET;
			} else if (type.equals("get")) {
				mType = ALIQType.GET;
			} else if (type.equals("result")) {
				mType = ALIQType.RESULT;
			}
			return mType;
		}
		return null;
	}

}
